package pnca;

import java.lang.reflect.*;
import java.util.logging.Level;

/**
 * The execution adapter executes the user selected analytics module on the user
 * selected input files
 *
 * @author Brett Yasutake
 * @author Niko Simonson
 */
public class ExecutionAdapter {

    private static ProvenanceAdapter pAdapter; // Provenance adapter to log exceptions

    /**
     * The execution adapter uses java reflection to execute the selected analytics
     * module, breaking the analysis into smaller partitions if necessary.
     * 
     * @param moduleName    the user selected analytics module
     * @param status        status adapter to communicate with the UI
     * @param selectedFiles the user selected input files
     * @param initialized   initialized boolean
     */
    public static void runAnalysis(String moduleName, StatusAdapter status, String[] selectedFiles, boolean initialized) {

        try {
            moduleName = Constants.ANALYTICSPACKAGE + moduleName; // Fully qualified name
            
            // Parameters via java reflection for analytics module's runAnalysis
            // Status adapter and string array (file names)
            Class[] paramStatus = new Class[1];
            Class[] paramSelectedFiles = new Class[1];
            Class[] paramInitialize = new Class[2];

            // Specifying  the type
            paramStatus[0] = StatusAdapter.class;
            paramSelectedFiles[0] = String[].class;

            paramInitialize[0] = StatusAdapter.class;
            paramInitialize[1] = int.class;

            Method method;

            method = Class.forName(moduleName).getDeclaredMethod("getMaxIterations");
            int MAXLENGTH = (int) method.invoke(null);
            int segment = 0;
            int segLength = 0;
            int iteration = 0;
            String[] chosenFiles;   // Subset of files to analyze

            

            long totalTime = 0;

            // If number of files is greater than maxiterations, split execution
            // into multiple runs of maxlength files at a time
            while (segment < selectedFiles.length) {
                segLength = selectedFiles.length - segment;
                if (segLength > MAXLENGTH) {
                    segLength = MAXLENGTH;
                }
                chosenFiles = new String[segLength];
                for (int i = 0; i < segLength; ++i) {
                    chosenFiles[i] = selectedFiles[i + segment];
                }
                
                // Reflection call to analytics module's setFiles method
                method = Class.forName(moduleName).getDeclaredMethod("setFiles", paramSelectedFiles);
                method.invoke(null, new Object[]{chosenFiles});

                // Reflection call to analytics module's initialize function, passing  it the status adapter
                if (!initialized) {
                    method = Class.forName(moduleName).getDeclaredMethod("initialize", paramInitialize);
                    method.invoke(null, status, iteration);

                }

                // Reflection call to analytics module's runAnalysis, passing it the status adapter
                method = Class.forName(moduleName).getDeclaredMethod("runAnalysis", paramStatus);
                totalTime += (long) method.invoke(null, status);

                ++iteration;
                segment += segLength;

            } // end while

            System.err.println("Total execution time (milliseconds): "
                    + totalTime);
            status.reportMessage("Total execution time (milliseconds): "
                    + totalTime);

        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            pAdapter.log(Level.SEVERE, "exception caught in execution adapter", e);
        }
    }
}
